package com.umpay.business.consume.impl;

import com.umpay.business.consume.ConsumeNotifyBusinessService;
import com.umpay.controller.base.AbstractController;
import com.umpay.dict.DataDict;
import com.umpay.dict.XmlData;
import com.umpay.dict.retcode.MerAccessEC;
import com.umpay.dto.UMFResponse.Message;
import com.umpay.dto.UMFResponse.Message.Meta;
import com.umpay.dto.merAccess.req.consume.ConsumeNetBankNotifyReq;
import com.umpay.dto.merAccess.res.consume.ConsumeNetBankNotifyRes;
import com.umpay.dto.merBusi.req.consume.ConsumeNetBankConfirmBusiReq;
import com.umpay.dto.merBusi.res.consume.ConsumeNetBankConfirmBusiRes;
import com.umpay.exception.BusinessException;
import com.umpay.feign.client.ConsumeBusiServerFeignClient;
import com.umpay.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Service
public class ConsumeNotifyBusinessServiceImpl extends AbstractController implements ConsumeNotifyBusinessService {

	public static final Logger log = LogManager.getLogger(ConsumeNotifyBusinessServiceImpl.class);
	
	private NotifyMerUtil notifyMerUtil;
	@Autowired
	private ConsumeBusiServerFeignClient consumeBusiServerFeignClient;
	
	@Override
	public ModelAndView consumeNetBankFrontNotify(ConsumeNetBankNotifyReq consumeNetBankNotifyReq) {
		
		log.info(String.format("【网银消费前台通知】1、前台通知接收参数为：【%s】", consumeNetBankNotifyReq));
		
		Map<String,Object> reqMap = EntityMapUtil.transBean2Map(consumeNetBankNotifyReq);
		
		String rpid = StringUtils.trim(reqMap.get(XmlData.RPID));
        if (StringUtils.isEmpty(rpid)) {
            rpid = RpidUtils.getRpid();
            reqMap.put(XmlData.RPID,rpid);
        }
        Map<String, Object> resMap = null;
        try{
		    log.info(String.format("rpid[%s]||【网银消费前台通知】2、验证签名数据是否正确", rpid));
			Map<String,Object> paraMap = new HashMap<String,Object>();
			paraMap.putAll(reqMap);
			String reqSign = StringUtils.trim(reqMap.get(XmlData.SIGN));
			String key = StringUtils.trim(PropertiesUtil.getBusiStrValue("payWeb.desSign.key",""));
			boolean testSign = HashSignHelper.verifySign(reqSign, paraMap, key); 
			if(!testSign){
				throw new BusinessException(MerAccessEC.MERSIGN_ERR,"验签失败");
			}
			
			reqMap.put(XmlData.NOTIFYTYPE, DataDict.NOTIFY_MER_FRONT);
    		String payMsg = StringUtils.trim(reqMap.get(XmlData.RETMSG));
    		if(!StringUtils.isEmpty(payMsg)){
    			//取支付网关加密key
        		String deskey = StringUtils.trim(PropertiesUtil.getBusiStrValue("payGate.decrypt.Key",""));
        		payMsg = DES3Util.decrypt3DES(payMsg,deskey);
        		reqMap.put(XmlData.RETMSG,payMsg);	
    		}
			
            //组织请求业务线记账处理请求数据
            ConsumeNetBankConfirmBusiReq consumeNetBankConfirmBusiReq = getConsumeNetBankConfirmBusiReqData(reqMap);
            log.info(String.format("rpid[%s]||【网银消费前台通知】3、通知业务线网银消费结果", consumeNetBankConfirmBusiReq));
            Message<ConsumeNetBankConfirmBusiRes> data = this.consumeBusiServerFeignClient.merConsumeNetBankConfirm(consumeNetBankConfirmBusiReq);
            
            if(data==null||data.getData()==null){
            	log.info("【网银消费前台通知】业务系统响应内容为空！");
            	throw new BusinessException(MerAccessEC.MERBUSI_RESPOND_ERR, "业务系统响应异常！");
            }
            
            ConsumeNetBankConfirmBusiRes merBusiRes = data.getData();
            resMap = EntityMapUtil.transBean2Map(merBusiRes);
            if(merBusiRes.getNotifyData()!= null){
            	Map<String,Object> toMerData =  merBusiRes.getNotifyData().get(0);
            	resMap.putAll(toMerData);
            }else{
            	resMap.put(XmlData.SERVICE, "mer_consume_notify");
            }
            
            //组织需要返回的数据
            Meta meta = new Meta(StringUtils.trim(resMap.get(XmlData.RETCODE)), StringUtils.trim(resMap.get(XmlData.RETMSG)));
            Map<String, String> req = PropertiesUtil.OrganizationalDataFromConfigFile(resMap,"consume_notify_backrule",",");
            Message<Map<String, String>> message = new Message<Map<String, String>>(meta, req, null);
            String retUrl = StringUtils.trim(resMap.get(XmlData.RETURL));
            //String url = notifyMerUtil.doRetUrl(resMap, StringUtils.trim(resMap.get(XmlData.RETURL)), "mer_recharge_return_backRule");// sign 签名
            //log.info(String.format("前台通知商户的url=%s", url));
            //RedirectView rv = new RedirectView(url);
            return new ModelAndView("redirect:" + retUrl + "?" + getAssembleFrontUrl(message));
            
		}catch(BusinessException e){
            log.error(String.format("【网银消费前台通知】消费通知异常：[%s：%s]",
                    e.getCode(), e.getMessage()));
            throw new BusinessException(e.getCode(), e.getMessage());
		}catch(Exception e){
            log.error(String.format("【网银消费前台通知】消费通知异常：[%s：%s]",
                    MerAccessEC.SYSTEM_ERR, e.getMessage()));
            throw new BusinessException(MerAccessEC.SYSTEM_ERR, "系统忙，请稍后再试");
        }
	}

	private ConsumeNetBankConfirmBusiReq getConsumeNetBankConfirmBusiReqData(Map<String, Object> reqMap) {
		
		ConsumeNetBankConfirmBusiReq consumeNetBankConfirmBusiReq = new ConsumeNetBankConfirmBusiReq();
		
		consumeNetBankConfirmBusiReq.setRpid(StringUtils.trim(reqMap.get(XmlData.RPID)));
		consumeNetBankConfirmBusiReq.setOrderId(StringUtils.trim(reqMap.get(XmlData.ORDERID)));
		consumeNetBankConfirmBusiReq.setOrderDate(StringUtils.trim(reqMap.get(XmlData.ORDERDATE)));
		consumeNetBankConfirmBusiReq.setMerId(StringUtils.trim(reqMap.get(XmlData.MERID)));
		consumeNetBankConfirmBusiReq.setUserId(StringUtils.trim(reqMap.get(XmlData.USERID)));
		consumeNetBankConfirmBusiReq.setAmount(StringUtils.trim(reqMap.get(XmlData.AMOUNT)));
		consumeNetBankConfirmBusiReq.setBproductId(StringUtils.trim(reqMap.get(XmlData.BPRODUCTID)));
		consumeNetBankConfirmBusiReq.setPproductId(StringUtils.trim(reqMap.get(XmlData.PPRODUCTID)));
		consumeNetBankConfirmBusiReq.setTrace(StringUtils.trim(reqMap.get(XmlData.TRACE)));
		consumeNetBankConfirmBusiReq.setTradeNo(StringUtils.trim(reqMap.get(XmlData.TRADENO)));
		consumeNetBankConfirmBusiReq.setPayState(StringUtils.trim(reqMap.get(XmlData.PAYSTATE)));
		consumeNetBankConfirmBusiReq.setVersion("1.0");
		return consumeNetBankConfirmBusiReq;
	}


	@Override
	public Message<ConsumeNetBankNotifyRes> consumeNetBankBackNotify(ConsumeNetBankNotifyReq consumeNetBankNotifyReq,HttpServletResponse response) {
		log.info(String.format("【网银消费后台通知】1、后台通知接收参数为：【%s】", consumeNetBankNotifyReq));
		Map<String,Object> reqMap = EntityMapUtil.transBean2Map(consumeNetBankNotifyReq);
		log.info(String.format("解析支付网关通知请求的参数为：%s", reqMap));
		String rpid = "";
		String retCode = "";
		try {
    		// 获取rpid
    		rpid = StringUtils.trim(reqMap.get(XmlData.RPID));
    		if (StringUtils.isEmpty(rpid)) {
    			rpid = RpidUtils.getRpid();
            }
    		reqMap.put(XmlData.RPID,rpid);
    		
    		log.info(String.format("2、【网银消费后台通知】验证支付网关签名数据", rpid));
            Map<String, Object> paraMap = new HashMap<String, Object>(reqMap);
            String reqSign = StringUtils.trim(reqMap.get(XmlData.SIGN));
            String key = StringUtils.trim(PropertiesUtil.getStrValue("payGate.desSign.key"));
            boolean testSign = HashSignHelper.verifySign(reqSign, paraMap, key); 
            if(!testSign){
            	throw new BusinessException(MerAccessEC.MERSIGN_ERR,"验证网关签名失败");
            }
            
            reqMap.put(XmlData.NOTIFYTYPE, DataDict.NOTIFY_MER_BANK);
    		String payMsg = StringUtils.trim(reqMap.get(XmlData.RETMSG));
    		if(!StringUtils.isEmpty(payMsg)){
    			//取支付网关加密key
        		String deskey = StringUtils.trim(PropertiesUtil.getBusiStrValue("payGate.decrypt.Key",""));
        		payMsg = DES3Util.decrypt3DES(payMsg,deskey);
        		reqMap.put(XmlData.RETMSG,payMsg);	
    		}
    		
    		ConsumeNetBankConfirmBusiReq consumeNetBankConfirmBusiReq = getConsumeNetBankConfirmBusiReqData(reqMap);
            log.info(String.format("rpid[%s]||【网银消费后台通知】3、通知业务线网银消费结果", consumeNetBankConfirmBusiReq));
            Message<ConsumeNetBankConfirmBusiRes> data = this.consumeBusiServerFeignClient.merConsumeNetBankConfirm(consumeNetBankConfirmBusiReq);
		    retCode = MerAccessEC.SUCCESS;
		} catch (BusinessException e){
            log.error("【网银消费后台通知】业务异常", e);
            retCode = MerAccessEC.SYSTEM_ERR;
        }catch (Exception e){
            log.error("【网银消费后台通知】异常", e);
            retCode = MerAccessEC.SYSTEM_ERR;
        }
		StringBuilder sb = new StringBuilder();
		sb.append(XmlData.RETCODE).append("=").append(retCode);
		PrintWriter pw;
		try {
			pw = response.getWriter();
			String ret = sb.toString();
			log.info(String.format("rpid[%s]||4、【网银消费后台通知】返回给支付网关数据为：%s", rpid, ret));
			pw.write(ret);
			pw.close();
		} catch (IOException e) {
			log.info(MerAccessEC.SYSTEM_ERR,"【网银消费后台通知】响应支付网关异常！");
			e.printStackTrace();
		}
		return null;
	}
}
